package com.cash.channel.web.signature;

import com.cash.channel.api.exception.CashChannelException;
import com.cash.channel.api.util.ObjectUtil;
import com.cash.channel.web.model.RequestModel;
import com.cash.channel.web.utils.GzipTool;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import java.nio.charset.StandardCharsets;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

@Slf4j
public class SignatureTool {

    public static void checkSign(RequestModel requestModel, String publicKeyStr) throws CashChannelException {
        try {
            String content = buildSignContent(requestModel);
            final RSAPublicKey publicKey = RSATool.parseRSAPublicKey(publicKeyStr);
            final boolean verify = RSATool.rsaVerifySignByPublicKey(publicKey, content.getBytes(StandardCharsets.UTF_8), Base64.decodeBase64(requestModel.getSign()));
            if (!verify) {
                throw new CashChannelException("验签未通过");
            }
            if (requestModel.getEncrypt() != null && 1 == requestModel.getEncrypt()) {
                // 需要解密
                final byte[] bytes =
                        RSATool.rsaDecryptByPublicKey(publicKey, Base64.decodeBase64(requestModel.getEncryptKey()));
                assert bytes != null;
                String originEncryptKey = new String(bytes, StandardCharsets.UTF_8);
                requestModel.setEncryptKey(originEncryptKey);
                byte[] originDataBytes = AESTool.aesDecrypt(Base64.decodeBase64(requestModel.getData()), originEncryptKey);
                if (1==requestModel.getCompress()) {
                    originDataBytes = GzipTool.unCompress(originDataBytes);
                }
                requestModel.setData(new String(originDataBytes, StandardCharsets.UTF_8));
            } else if (Base64.isBase64(requestModel.getData())) {
                byte[] originDataBytes = Base64.decodeBase64(requestModel.getData());
                if (1==requestModel.getCompress()) {
                    originDataBytes = GzipTool.unCompress(originDataBytes);
                }
                requestModel.setData(new String(originDataBytes, StandardCharsets.UTF_8));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CashChannelException("验签失败："+e.getMessage());
        }

    }

    public static String buildSignContent(RequestModel requestModel) throws CashChannelException {
        if (requestModel == null) {
            throw new CashChannelException("请求参数不能为空");
        }
        try {
            Map<String, Object> objectMap = ObjectUtil.objectToMap(requestModel);
            SortedMap<String, Object> paramMap = new TreeMap<>();
            for (String key : objectMap.keySet()) {
                if ("sign".equals(key)) {
                    continue;
                }
                final Object val = objectMap.get(key);
                if (val == null) {
                    continue;
                }
                if (val instanceof String && ((String) val).length() == 0) {
                    continue;
                }
                paramMap.put(key, val);
            }
            StringBuffer sb = new StringBuffer();
            for (String key: paramMap.keySet()) {
                sb.append("&"+key+"="+paramMap.get(key));
            }
            return sb.substring(1);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CashChannelException("构建待签名正文错误");
        }
    }

}
